package com.kk.xhr.model.service.impl;

import com.kk.xhr.common.pojo.RecruitStatusEnum;
import com.kk.xhr.model.assembler.RecruitStructKit;
import com.kk.xhr.model.dao.RecruitDynamicSqlSupport;
import com.kk.xhr.model.dao.RecruitInterviewDynamicSqlSupport;
import com.kk.xhr.model.dao.RecruitInterviewMapper;
import com.kk.xhr.model.dao.RecruitMapper;
import com.kk.xhr.model.dto.PageDto;
import com.kk.xhr.model.dto.RecruitDTO;
import com.kk.xhr.model.dto.RecruitQueryRequestDTO;
import com.kk.xhr.model.entity.Recruit;
import com.kk.xhr.model.entity.RecruitInterview;
import com.kk.xhr.model.service.IRecruitService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.where.AbstractWhereDSL;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.mybatis.dynamic.sql.SqlBuilder.insertMultiple;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualToWhenPresent;
import static org.mybatis.dynamic.sql.SqlBuilder.isIn;
import static org.mybatis.dynamic.sql.SqlBuilder.isLikeWhenPresent;

/**
 * 招聘服务接口实现
 *
 * @author kkmystery
 * @version 1.0 2021/4/6
 * @since 1.0.0
 */
@Repository
@RequiredArgsConstructor
public class RecruitServiceImpl implements IRecruitService {
    private final RecruitMapper recruitMapper;
    private final RecruitInterviewMapper recruitInterviewMapper;
    private final RecruitStructKit instance = RecruitStructKit.INSTANCE;

    @Override
    public PageDto<RecruitDTO> queryPage(RecruitQueryRequestDTO dto) {
        long count = recruitMapper.count(dsl -> applyQueryArgs(dsl.where(), dto));
        if (0 == count) {
            return PageDto.empty();
        }
        return new PageDto<>(count, recruitMapper.select(dsl -> applyQueryArgs(dsl.where(), dto)
            .orderBy(RecruitDynamicSqlSupport.id.descending())
            .limit(dto.getLimit())
            .offset(dto.getOffset()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList()));
    }

    @Override
    public PageDto<RecruitDTO> queryPage(Long userId, RecruitQueryRequestDTO dto) {
        List<Long> ids = recruitInterviewMapper.select(dsl -> dsl
            .where(RecruitInterviewDynamicSqlSupport.interviewerId, isEqualTo(userId)))
            .stream()
            .map(RecruitInterview::getRecruitId)
            .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(ids)) {
            return PageDto.empty();
        }
        long count = recruitMapper.count(dsl -> applyQueryArgs(dsl.where(), dto).and(RecruitDynamicSqlSupport.id, isIn(ids)));
        if (0 == count) {
            return PageDto.empty();
        }
        return new PageDto<>(count, recruitMapper.select(dsl -> applyQueryArgs(dsl.where(), dto)
            .and(RecruitDynamicSqlSupport.id, isIn(ids))
            .orderBy(RecruitDynamicSqlSupport.id.descending())
            .limit(dto.getLimit())
            .offset(dto.getOffset()))
            .stream()
            .map(instance::toDto)
            .collect(Collectors.toList()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(Collection<Long> userIds, RecruitDTO dto) {
        if (CollectionUtils.isEmpty(userIds)) {
            return;
        }
        Recruit entity = instance.toEntity(dto);
        recruitMapper.insertSelective(entity);
        List<RecruitInterview> recruitInterviewList = userIds.stream().map(userId -> new RecruitInterview().withInterviewerId(entity.getId()).withRecruitId(userId))
            .collect(Collectors.toList());
        recruitInterviewMapper.insertMultiple(insertMultiple(recruitInterviewList)
            .into(RecruitInterviewDynamicSqlSupport.recruitInterview)
            .map(RecruitInterviewDynamicSqlSupport.recruitId).toProperty("recruitId")
            .map(RecruitInterviewDynamicSqlSupport.interviewerId).toProperty("interviewerId")
            .build().render(RenderingStrategies.MYBATIS3));
    }

    @Override
    public Optional<RecruitDTO> query(Long id) {
        return recruitMapper.selectByPrimaryKey(id).map(instance::toDto);
    }

    @Override
    public void modify(RecruitDTO dto) {
        recruitMapper.updateByPrimaryKeySelective(instance.toEntity(dto));
    }

    @Override
    public void modifyStatus(Long id, RecruitStatusEnum status) {
        if (null == status) {
            return;
        }
        recruitMapper.updateByPrimaryKeySelective(new Recruit().withId(id).withStatus(status.getValue()));
    }

    @Override
    public void deleteRef(Long recruitId) {
        recruitInterviewMapper.delete(dsl -> dsl.where(RecruitInterviewDynamicSqlSupport.recruitId, isEqualTo(recruitId)));
    }

    private <T extends AbstractWhereDSL<T>> T applyQueryArgs(T where, RecruitQueryRequestDTO dto) {
        where.and(RecruitDynamicSqlSupport.title, isLikeWhenPresent(dto.getTitle()).then(s -> "%" + s + "%"))
            .and(RecruitDynamicSqlSupport.positionId, isEqualToWhenPresent(dto.getPositionId()));
        if (null != dto.getFrom()) {
            where.and(RecruitDynamicSqlSupport.form, isEqualTo(dto.getFrom().getValue()));
        }
        if (null != dto.getStatus()) {
            where.and(RecruitDynamicSqlSupport.status, isEqualTo(dto.getStatus().getValue()));
        }
        return where;
    }
}
